﻿#include "VideoFrameFilter.h"
#include <iostream>

extern "C"
{
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
}

VideoFrameFilter::VideoFrameFilter()
{

}

int VideoFrameFilter::init(int inWidth, int inHeight, AVPixelFormat inFmt, int outWidth, int outHeight, AVPixelFormat outFmt)
{
    m_sws_ctx = sws_getContext(inWidth, inHeight, inFmt, outWidth, outHeight, outFmt, SWS_BILINEAR, 0, 0, 0);
    if (!m_sws_ctx) {
        std::cerr << "Could not create scaling context" << std::endl;
        return -1;
    }

    m_srcW = inWidth;
    m_srcH = inHeight;
    m_srcFmt = inFmt;
    m_dstW = outWidth;
    m_dstH = outHeight;
    m_dstFmt = outFmt;

    return 0;
}

void VideoFrameFilter::uninit()
{
    sws_freeContext(m_sws_ctx);
}

VideoFrameFilter::~VideoFrameFilter()
{
    uninit();
}

// Function to convert AVFrame to YUV420P format
AVFrame *VideoFrameFilter::filter(AVFrame *src_frame)
{
    if (!src_frame)
        return nullptr;

    if(src_frame->height != m_srcH || src_frame->width != m_srcW || (AVPixelFormat)src_frame->format != m_srcFmt) {
        std::cerr << "Invalied arguments in VideoFrameFilter::filter. " << std::endl;
        return nullptr;
    }

    // Allocate an AVFrame structure for the destination frame
    AVFrame* dst_frame = av_frame_alloc();
    if (!dst_frame) {
        std::cerr << "Could not allocate destination frame" << std::endl;
        return nullptr;
    }

    dst_frame->pts = src_frame->pts;
    dst_frame->pkt_duration = src_frame->pkt_duration;

    if(m_dstH == m_srcH && m_dstW == m_srcW && m_dstFmt == m_srcFmt) {
        av_frame_ref(dst_frame, src_frame);
        return dst_frame;
    }

    // Set the properties for the destination frame
    dst_frame->format = m_dstFmt;
    dst_frame->width = m_dstW;
    dst_frame->height = m_dstH;

    // Allocate the buffers for the destination frame
    if (av_frame_get_buffer(dst_frame, 0) < 0) {
        std::cerr << "Could not allocate destination frame buffer" << std::endl;
        av_frame_free(&dst_frame);
        return nullptr;
    }

    // Perform the scaling conversion
    int ret = sws_scale(m_sws_ctx, src_frame->data, src_frame->linesize, 0, src_frame->height,
              dst_frame->data, dst_frame->linesize);

    if(ret < 0) {
        std::cerr << "An error occurred when scaling frame, errCode: " << ret << std::endl;
        av_frame_free(&dst_frame);
        return nullptr;
    }

    return dst_frame;
}
